#i should check stackexchange more often
Explore tagged Tumblr posts
Text
#i should check stackexchange more often#Ijust wanted to know if it would work in thecontext im using it...
3 notes
¡
View notes
Text
Just What I Needed (Chapter 3)
Cross-posting my fics while AO3 is down! This is a multi-chapter fic; please check out the contents page for additional tags, overall CWs and other chapters before reading!
Title: Just What I Needed (Chapter 3)
Fandom: Supernatural
Rating: E
Ship: Destiel
Chapter 3 CWs: none
Summary: All Sam and Dean have to their names right now is $200, a '67 Chevy Impala, and a lead.
Dean dropped Sam off outside the library. Sam waved, wishing him a good date and reminding him to be careful. Dean was relaxed. Heâd managed to wash his hair under a standpipe at the gas station earlier, and he had one of his last clean shirts on. He knew he didnât exactly look his best, but at least Castiel probably wouldnât be able to guess that he was effectively homeless.
He parked two blocks away from the Cheesecake Factory at precisely 6.45, giving him enough time to walk the rest of the way. He didnât like to park right outside in case his jilted date tried to follow him. It wouldnât do to have some angry guy memorising his plates. He walked briskly, not because he was cold, but actually a little excited. He tried to contain himself, but it was a long time since heâd been on anything that had even the semblance of a real date. He might have been out here scamming older guys for food, but they were out to get something for themselves too. He just didnât usually give it to them.
Reminding himself that, no matter how pleasant the target, this was still just a scam, Dean hurried inside. Castiel was waiting just inside of the door. He smiled when he saw Dean.
âAaron, I presume?â
âThatâs me. Shall we grab a table?â
âYes, we should.â
After they were situated, with two glasses of water and their food on the way, Castiel decided it was time to start the conversation.
âI hope this is okay. The restaurant, I mean. I never feel comfortable at expensive places.â
âOh, no, itâs fine. I get that.â Dean did get it. He was all about quantity over quality, especially recently.
âGood,â Castiel responded, before falling silent. Dean waited for a couple of minutes, but there was no follow-up. Odd. Maybe Castiel was nervous. Okay, Dean could work with that.
âSo, uh, do you come here often?â
Dean kicked himself internally. Why was that the thing that came out of his mouth? If heâd had a brain, heâd be dangerous.
âNo, I do not frequent the Cheesecake Factory. I mainly eat at home,â Castiel answered the question, apparently taking it at face value. He looked down at his drink. More silence. Dean began to feel a bit awkward. The conversation just wasnât flowing the way it had seemed to earlier. It was⌠weird.
âHey, uh, are you okay?â he asked.
âYes. Sorry. My people skills are⌠rusty. I mainly talk to computers. I havenât been on a proper date since⌠well, I canât remember, actually. Iâve forgotten what to do.â
Dean laughed gently. That made two of them.
âWell, you were pretty conversational earlier. Just stick with that.â
âOh. That. Texting is easier than face to face interactions. And the questions thing â I, uh, saw that on stackexchange. Iâm nowhere near that smooth in real life.â
Well, that made sense. Dean felt just the smallest twinge of disappointment, but he shelved it. If the date was bad, he wouldnât feel guilty for cutting out early.
âI think, this is the part where I ask you to tell me about yourself, is it not?â Castiel continued. âHow long have you been in town?â
âJust a few days. Youâre local?â
âYep, born and bred. You here for long?â
âNot sure yet. Probably not. We move around a lot.â
âWe?â
Damn. Dean usually went out of his way to avoid giving any personal information to his dates. Castiel was more observant than he was used to. Most of the guys he went out with just wanted to talk about themselves. Oh well, he supposed he could give a few details, as long as they werenât identifying.
âYeah, Iâm with my family. My Dad, and my kid brother.â
âYour dad? How old did you say you were again?â
âI didnât, but Iâm 24.â Dean lied. Really, he was 20, but a lot of guys were put off by that, and the ones that werenât tended to be trouble. âFamily business. I help out and take care of Sammy.â
âThat sounds pleasant. I havenât seen my brothers for a long time. Theyâre not⌠the best people.â
Oh. Okay. Awkward, and a little oversharing. Castiel wasnât really what Dean had expected, but, somehow, he found that he didnât mind. It was honestly just nice to meet someone who liked to listen as much as talk.
âSorry to hear that, man. Having a brother⌠itâs awesome. Sammyâs the greatest kid. Does good in school, everyone likes him, you know. Never gets in trouble. Give him some apple pie and heâs happy as Larry.â
Dean lit up when he was talking about Sam, and Castiel noticed, smiling at him softly. It was a kind smile. It made Dean feel warm. Not many people looked at him like that these days.
âWhatâs the family business?â
âOh, you know. Contracting. Short jobs, different cities, that sort of thing. We mostly live on the road.â
âSounds interesting. Tiring, I imagine, but it must feel⌠freeing.â If Castiel had noticed how Dean had deflected the question, he didnât comment. âIâm chained to a desk most days, Iâm afraid. Not a very exciting life.â
âWell, thank god you met me,â Dean quipped, before his curiosity got the better of him. âActually, if this is your first date in a while⌠why did you ask me out?â
âI donât know. I hadnât even opened Grindr in, oh, mustâve been months. Today I just decided to check it out, see whatâs out there, and there you were, right at the top. I didnât know youâd just come into town. But it seems, I donât know, serendipitous.â
As he said this, Castiel met Deanâs eyes, and held his gaze for the longest they had managed so far. Dean could tell that he was completely sincere. He almost found himself agreeing. Castielâs eyes were truly striking. Dean felt like he was at risk of answering any question Castiel asked as long as he was looking into his eyes.
Their food arrived, and Castiel got to work on his quickly, with Dean taking it considerably slower. The conversation was moving more naturally now. They talked about Castielâs job, which sounded just as boring as he claimed it was, their hobbies (Dean left several off the list), music, and a bit more about their families. Dean was careful not to give anything else away. Castiel didnât go into much detail about his, either. What he did say made it sound pretty complicated. Dean could relate. Neither of them pried beyond what they were willing to share.
Dean almost jumped out of his chair when he felt his phone ring. He quickly checked his watch â how was it 8.30 already? He hadnât been looking at the time at all. He supposed he had just been enjoying Castielâs company.
âSorry, I gotta take this.â
âNo problem.â
Dean walked away from the table and answered the phone.
âHi, Sammy.â
âReady to go?â
Dean hesitated, glancing back at Castiel, who was still sitting at the table. God, he was good-looking. A tiny part of him wanted to stay.
âDean? Come on, Iâm hungry.â
âRight, right. Sorry. Iâll be right there.â
He hung up and returned to the table. No need for a fake frown; he actually felt bad about leaving. Castiel clearly didnât go out much. Dean felt like he was wasting a rare opportunity for him.
âCastiel, Iâm so sorry. I have to go. My Dad has to go to work, so I gotta go home and take care of Sammy. Sorry, I was supposed to have the night free.â
Castiel was silent for a few seconds, before turning his face towards Dean with an understanding expression.
âItâs okay. Here, letâs get your food packed up.â He motioned for a waiter to come to the table. âCould we get this food to go? And add an apple pie to that, and the bill, please.â
âApple pie?â
âSammyâs favourite, right?â
Dean was taken aback. Now he felt really guilty.
âHey, Aaron, I had a great time tonight. Could I get your number?â
âWhat? Oh, right, of course.â
Dean had been asked this after a date before of course. This time, though, he gave Castiel his real number. He felt his phone buzz in his pocket as Castiel drop-called him.
âThere, now youâve got mine. Ah, and just in time,â he said, as the waiter returned with the food. He handed the bags to Dean, who accepted them gratefully. âText me when you get home, okay?â
âUh, sure. Thanks, Castiel. Be seeing you.â
âI hope so.â
Dean turned and half-ran out of the restaurant. Castiel would hopefully assume it was because he was rushing home, but really Dean just didnât know how to respond. When he got back to the car, he pulled out his phone and saved Castielâs number, grinning stupidly. Yeah, he was totally smitten.
He got back to the library at 8.55. Sam was waiting.
âYouâre late.â
âFive minutes! And I got you pie.â
âWhat? How did you manage that?â
âThe guy. He ordered it.â
Sam gave him a sidelong look. âAnd? How was it?â
âIt was nice. He was nice.â
âThatâs good. Shame youâre not gonna see him again.â
Dean felt a slight pang of sadness. âRight. Yeah. Iâm not into second dates, anyway.â
There was a faint buzzing sound, which Dean realised had come from his phone. He opened it to check the notification. Grindr. He opened it, just to see what it was.
hi
u into older
?
________________
Well, it was a bit soon after his last date, but maybe Dean could book in dinner for later in the week. It would give him one less thing to worry about.
iâm open
________________
Good start. Not shutting it down, but not looking like he was into it either. Dean had discovered that if he came on too strong, they didnât feel as inclined to spend money on him.
u avail?
[location]
here
now
________________
Yikes.
buy a guy dinner first?
iâm free tomorrow
________________
no dinner
1 hr
p2p
200
u come or not?
________________
Dean wracked his brain. What was âp2pâ, again? Drugs? No, drugs was âpnpâ, or sometimes âpArtyâ. No, âp2pâ was⌠oh, right. Pay to play. 200. That mustâve meant $200. Damn.
Dean was under no illusion exactly what he would be doing for that $200. To be honest, heâd considered it before, sometime after they got down to their last $500. He just hadnât really known how to actually, you know, find a job.
pics?
________________
[image]
[image]
[image]
________________
Well, one out of those three was not exclusively a dick pic. The guy was definitely older than Dean, but still only looked to be about early 50s. He wasnât stunningly attractive or anything, but not bad. Dean made up his mind.
ok
just got off work
can I shower at your place?
________________
sure
________________
be right there
________________
Dean looked over at Sam, who was working on his food.
âHey, Sammy. Iâve gotta go, uh, take care of something. Iâm gonna bring the car, so you just lock yourself in, alright? It wonât take long.â
âWhere are you going? Hunting? Can I come?â
âNo, and no. Itâs just⌠a thing. Donât worry about it. Iâll be back before you know it.â
âOkay, sure. Just be careful, alright?â
âYeah, yeah. Of course.â
Dean sped across town and parked two streets away from the location. He grabbed his phone, leaving the car keys with Sam. He reached the house and rang the doorbell, hopping nervously from one foot to the other. The man opened the door and looked him up and down.
âHi. Come in.â
âThanks.â Dean ducked inside, heading straight to the bathroom. In his haste, he missed the text that came through to his phone.
Hey, Aaron. Did you make it home okay?
- Castiel: 21.20
#fandom#fanfiction#ao3#fanfic#destiel#deancas#supernatural#castiel supernatural#dean winchester#sam winchester#ao3 fic#ao3 down
0 notes
Text
Player movement
This is one entry in a multi-part series. If you haven't read the start of the sandbox demo series, start reading here.
The time has finally come to let the player move around. There are a few ways to handle movement in a 2D game, depending on the type of game. If I were making a precision platformer, I would probably just want fixed speed movement, but Iâm not so Iâll go for acceleration with a maximum speed.
Even with that approach there are multiple options though. Here's an equation I've used in the past:
\[v\left(t\right)=a+fv\left(t-1\right)\]
//This is what it would look like in code: player.Velocity *= f; // 0 < f < 1 player.Velocity += a;
\(a\) is the acceleration of the player or entity and \(f\) is the "decay" or friction, generally set to a high decimal value like 0.8. The maximum velocity in this approach is equal to \(\frac{a}{1-f}\). I'm sure you could prove that with limits or something, but I'm going to take the "if it seems to work it's probably right" approach. If I let \(a=1\), the formula evaluates to:
\[v\left(t\right)=s\left(1-f\right)+fv\left(t-1\right)\]
where \(f\) represents the accleration and \(s=v_{\max}\). Oh, and if we're going for low-level optimization, I can cut out a multiplication operation with this simplification:
\[v\left(t\right)=s+f\left(v\left(t-1\right)-s\right)\]
Mathematically, this formula works. In practice, the code is going to have more trouble with it. \(t\) is supposed to represent time, but computers don't always have the same time gap between frames. If I were to lock the framerate I could ignore that issue, but nobody likes framerate locks. To fix this, I'll move outside of algebra and into programming math. Oh, and let's change \(s\) to \(m\) and \(f\) to \(a\) while we're at it.
\[v\rightarrow m+a\Delta t\left(v-m\right)\]
\(\Delta t\) can really be in any time format I want, as long as I set \(a\) accordingly.
So let's put this into code! I'll start with horizontal movement first, as that doesn't really require that I actually implement physics.
if (keyboardState.IsKeyDown(Keybinds.Left)) targetSpeed -= 10; if (keyboardState.IsKeyDown(Keybinds.Right)) targetSpeed += 10; player.Velocity = new Vector2(targetSpeed + (0.9f * (float)gameTime.ElapsedGameTime.TotalSeconds * (player.Velocity.X - targetSpeed)), player.Velocity.Y); player.Position += player.Velocity.ToPoint();
But that didn't work. I mean, it worked in terms of the scaling (my math was right!) but the actual speeds and positions that things were at were wrong. After some testing (some of which involved an actual stopwatch) I realized the problem. I had multiplied the acceleration by the time step, but not the velocity when moving the player. But after I did that, the player wouldn't move at all. I immediately realized the issue: the distance moved per time step is less than one. The positions of entities are stored as points (for reasons that will be explained later), and points use integer x and y values, rather than Vector2s which consist of floating point numbers. I wanted to preserve the exact-ness of the position but still allow for decimal positions, so I decided to comprimise with this little bit of code:
public Vector2 Velocity { get; set; } public Point PointPosition { get { return Position.ToPoint(); } }
C# properties are beautiful, aren't they. I may regret this change later on, but I'll deal with it then. For now, I have other issues. Almost everything is working properly at this point, but the acceleration isn't visible. I changed \(a\) to 0.999f, but even that still wasn't noticable. The time step was too small for my large \(a\) values. At this point I also realized another problem. In the case in which a time step takes longer than one second (which should never happen in theory), everything will break. I'm sure speedrunners would love that, but I'm not making this for speedrunners. I need to guarantee that my \(a\) term is always less than one. I also need to guarantee that my \(a\) term is properly distributed over a second no matter how many updates are contained within that second.
I thought about this puzzle for a while until I finally came to my conclusion: If this is possible to solve, I don't know how to do it. If you can think of a solution to this, tweet me or ask me the answer, because I seriously have no idea. For now, I'm just going to remove the time step factor from the acceleration. Goodbye delta t, you will be missed.
\[v\rightarrow m+a\left(v-m\right)\]
For testing purposes, I'm going to make the player speed be 24 tiles/s or 1.5 chunks/s.
Of course though, the player's velocity shouldn't change mid-air, should it? Or if it does, it should change MUCH slower. My formula doesn't easily allow for things like air control, so while I could probably implement it by changing the \(a\) term while the player isn't grounded, I'll just add a "is player grounded" check before trying to change their velocity. Note that I haven't actually implemented any code that tells me if the player is grounded. I'm just using placeholder variables for now.
Now that I'm done with horizontal velocity (yes, all of that was just for horizontal velocity), I'm going to move on to vertical stuff. I might be able to just use straight acceleration, but I don't really want the player to be clipping through the ground. There are "ray"cast solutions to that, but I'm just going to assume that the player won't be going at ground clipping speeds for now. Is that ignorant? Yes. Do I care? Yes, but I'm willing to overlook it for now.
So I'm going to use raw acceleration anyways, even though I said it was a bad idea. Otherwise it's gonna feel like the player is hanging on to a bunch of balloons whenever move. How does 1 chunk/s2 sound for acceleration due to gravity? I think it sounds fine, so I'm gonna use that.
Let's go back to the collision from last time, specifically this line:
anyCollide = true;
Instead of just checking if there are any collisions, I'm also going to eject the player from the tile. This essentially means that if a player is inside of a tile, I'm going to move them just enough outside of the tile that they are resting right beside the tile. This is where my concern about using Position and PointPosition came from. When using floats for physics, there is often an issue of vertical jitter where the player is displaced just out of the tile, falls back into the tile the next frame, and then is displaced outside in the next frame. Hopefully that won't happen here, but I should keep in mind the possibility that it could.
But how will I perform ejection in the first place? It's not actually quite as hard as it sounds. Remember that stackoverflow answer that was actually a gamedev stackexchange answer that I linked in the previous post? That specifically mentions vertical ejection, but I'll apply the same idea for both axes. However, I won't eject on both axes. If I did, stuff like this would happen all the time:
Where what I really want is this:
To fix that, I'll look for the axis which has the lowest intersection, and eject on that axis. I'll know which direction by checking which side of the original entity center the intersection is on.
if (currentRect.Intersects(tileRect)) { anyCollide = true; Rectangle intersection = Rectangle.Intersect(currentRect, tileRect); if (intersection.Width < intersection.Height) { if (intersection.Center.X > currentRect.Center.X) { e.Position += -Vector2.UnitX * intersection.Width; } else { e.Position += Vector2.UnitX * intersection.Width; } e.Velocity *= Vector2.UnitY; } else { if (intersection.Center.Y > currentRect.Center.Y) { e.Position += -Vector2.UnitY * intersection.Height; } else { e.Position += Vector2.UnitY * intersection.Height; } e.Velocity *= Vector2.UnitX; } }
It works! My problem now is that I have no jump. Adding a jump is easy, but making it only work while the player is grounded is trickier. You might not have noticed the flashing the the gif above due to the framerate of the gif, but the character was flashing between red and green every frame. This is actually a side effect of the jitter I mentioned earlier. The frame after the player is ejected from the ground, they're no longer intersecting the ground, and so they appear red again.
However, this is actually sort of weird behavior due to the semantics of how I programmed and arranged my code. By best guess has to do with the time step being so quick that -16 * UNIT_SIZE * gameTime.ElapsedGameTime.TotalSeconds, the delta-v on the y axis, is less than one.
After some quick testing, I discovered that my hypothesis was in fact incorrect. However, though I may have been wrong, I was certainly on the right track. Each frame, the position is not changed by the velocity, but by the velocity times the time step. Therefore, it would actually take four or five frames to accumulate enough delta-y to intersect the player again.
Creating a fix to this issue which is ignorant of the framerate is pretty tricky. One option is to do an additional intersection check with a rectangle expanded by one unit in every direction. Hopefully this new check can actually replace the old one, as if there is a collision with no intersection, the intersection width or height would be zero, as per the documentation.
I should be able to say that an entity is grounded if the collision pushes them up, or the height of an intersection is zero. It works... I think.
After a bit of testing I decided to increase the acceleration due to gravity, and everything seems to be working fi- oh wait, no, that's not right. I have accidentally implemented wall jumps. Let's fix this by checking the ejection direction of the expanded collision rectangle, and performing the old collision that we know worked.
And it works! The last change that I'm going to make for the post is to change the current lack of air control into a slower acceleration air control. I can do this by just cranking up the \(a\) value from earlier really high while the player isn't grounded.
// These code blocks are getting way too long. bool anyCollide = false; e.Grounded = false; Rectangle entityRect = e.GetCollisionRect(); for (int x = entityRect.Left; x < entityRect.Right + Game1.UNIT_SIZE; x += Game1.UNIT_SIZE) { for (int y = entityRect.Top; y < entityRect.Bottom + Game1.UNIT_SIZE; y += Game1.UNIT_SIZE) { Tile t = GetTile(new Point(x.FloorDivide(Game1.UNIT_SIZE), y.FloorDivide(Game1.UNIT_SIZE))); if (t != null && t.HasCollision) { Rectangle currentRect = e.GetCollisionRect(); Rectangle expandedRect = currentRect.InflateThrough(1, 1); // Uses extension function of Rectangle.Inflate to make a clean one-liner. Rectangle tileRect = new Rectangle(x.FloorDivide(Game1.UNIT_SIZE) * Game1.UNIT_SIZE, y.FloorDivide(Game1.UNIT_SIZE) * Game1.UNIT_SIZE, Game1.UNIT_SIZE, Game1.UNIT_SIZE); if (expandedRect.Intersects(tileRect)) { Rectangle expandedIntersect = Rectangle.Intersect(expandedRect, tileRect); if (expandedIntersect.Height < expandedIntersect.Width && expandedIntersect.Center.Y > expandedRect.Center.Y) e.Grounded = true; anyCollide = true; if (currentRect.Intersects(tileRect)) { Rectangle intersection = Rectangle.Intersect(currentRect, tileRect); if (intersection.Width < intersection.Height) { if (intersection.Center.X > currentRect.Center.X) { e.Position += -Vector2.UnitX * intersection.Width; } else { e.Position += Vector2.UnitX * intersection.Width; } e.Velocity *= Vector2.UnitY; } else { if (intersection.Center.Y > currentRect.Center.Y) { e.Position += -Vector2.UnitY * intersection.Height; } else { e.Position += Vector2.UnitY * intersection.Height; } e.Velocity *= Vector2.UnitX; } } } } } }
And in honor of another game created using XNA, here are some vertical hoiks.
They're a bit harder to control.
0 notes